Conversation
- Removed MCP server and admin web UI (breaking changes) - Fixed multi-byte character corruption, WebSocket auth, HTTP method handling
|
Warning Review limit reached
Next review available in: 16 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughVersion 0.3.0 narrows the interface to CLI commands, adds JSON listing and log following, records deployment views, hardens HTTP and WebSocket handling, fixes request and log decoding, and adds broad integration and coverage tests. ChangesCLI surface and release scope
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant PublicServer
participant Auth
participant ManifestStore
participant WsManager
Client->>PublicServer: Request deployment content
PublicServer->>Auth: Validate protected access
Auth-->>PublicServer: Authorization result
PublicServer->>ManifestStore: Record successful HTML hit
Client->>WsManager: Request live-reload upgrade
WsManager->>Auth: Validate protected WebSocket access
WsManager-->>Client: Accept or reject upgrade
WsManager->>WsManager: Ping clients and remove stale sockets
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 16
🧹 Nitpick comments (5)
test/global-setup.ts (1)
19-29: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winScope the sweep so it cannot delete a concurrent run's temp dirs.
The sweep removes every matching directory in the shared OS temp dir. If a second test run executes on the same machine, this teardown deletes directories that the other run still uses. That run then fails for an unrelated reason. Filter by modification time, or by a per-run prefix recorded at setup.
♻️ Proposed change — age-based filter
export function teardown(): void { const tmp = os.tmpdir(); + const startedAt = Date.now(); let removed = 0; for (const name of fs.readdirSync(tmp)) { if (!/^uptool-[a-z0-9-]+-/.test(name)) continue; + const full = path.join(tmp, name); try { - fs.rmSync(path.join(tmp, name), { recursive: true, force: true }); + // Skip anything touched very recently — likely owned by another run. + if (startedAt - fs.statSync(full).mtimeMs < 60_000) continue; + fs.rmSync(full, { recursive: true, force: true }); removed++; } catch {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/global-setup.ts` around lines 19 - 29, Update the cleanup loop around readdirSync in the global teardown to avoid deleting active concurrent-run directories: inspect each matching entry’s modification time and remove it only when it exceeds the chosen stale-age threshold. Preserve the existing recursive, forced removal and best-effort error handling for eligible entries.test/api.test.ts (1)
409-413: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
force: trueto the cleanup removal.
fs.rmSync(tmpDir2, { recursive: true })throws if the directory is already absent. A throw infinallyreplaces the original test failure and hides the root cause. Also consider guardingbigStore.flushNow(), which writes to the same directory.♻️ Proposed change
- fs.rmSync(tmpDir2, { recursive: true }); + fs.rmSync(tmpDir2, { recursive: true, force: true });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/api.test.ts` around lines 409 - 413, Update the cleanup in the test’s finally block to remove tmpDir2 with recursive and force options so an already-absent directory does not mask the original failure. Also guard bigStore.flushNow() as needed so cleanup does not write to or recreate the directory before removal.test/public.test.ts (1)
516-522: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the stale section header.
The header "Handler throw -> 500, not a dead daemon" sits directly above the "View counting" block. The handler-throw test is at line 568. Move or delete this header so the section markers match the tests below them.
🧹 Proposed fix
- // ------------------------------------------------------------------------- - // Handler throw -> 500, not a dead daemon - // ------------------------------------------------------------------------- - // ------------------------------------------------------------------------- // View counting (recordHit) // -------------------------------------------------------------------------🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/public.test.ts` around lines 516 - 522, Remove the stale “Handler throw -> 500, not a dead daemon” section header from above the “View counting (recordHit)” block; keep the existing handler-throw test and view-counting section marker aligned with their respective tests.test/storage.test.ts (1)
547-568: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThis test asserts a copy of the formula, not the production code.
Lines 563-564 reimplement the padding-aware base64 size estimate inline. The assertions then compare that inline copy against
Buffer.from(b64, "base64").length. The test passes even if the estimator insidesrc/storage/index.tsis wrong, because the production estimator is never called. Export the estimator and call it, or assert the limit behavior throughstore()with amax_file_sizeset just above and just below the true decoded size.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/storage.test.ts` around lines 547 - 568, Update the base64 size estimation test to exercise the production estimator used by storage code instead of duplicating its formula inline. Export and import that estimator from the relevant storage module, then call it for each padding case while retaining the decoded-length assertions; alternatively, test store() with max_file_size thresholds immediately above and below the true decoded size.test/ws.test.ts (1)
170-182: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winNarrow the fake timers to the heartbeat interval.
vi.useFakeTimers()also fakessetImmediate, whileconnectLr()waits on realwsI/O that runs in the Node event loop. Fake onlysetInterval/clearIntervalso the constructor captures the heartbeat clock without stalling the socket open.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/ws.test.ts` around lines 170 - 182, Update the timer setup in the heartbeat test around WsManager construction to fake only setInterval and clearInterval, leaving setImmediate and other real event-loop APIs available for connectLr() websocket I/O. Preserve the existing timer advancement and cleanup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@package.json`:
- Line 29: Update the test:coverage workflow so the CLI is built from current
source before coverage tests run. Prefer adding the existing build command to
the test:coverage script, or update the CLI setup in test/helpers.ts to invoke
the build before executing dist/cli.js.
In `@src/commands/deploy.ts`:
- Around line 198-208: Update the URL identifier selection around urlSlug in the
deploy command so any --update deployment uses opts.update as the stable
identifier, including when result.slug is populated or name lookup returns no
slug. Preserve the existing opts.name preference for new named deployments and
ensure watchTarget/watchSlug use the same stable identifier.
In `@src/commands/logs.ts`:
- Around line 51-57: Update the appended-log read flow around the read loop and
process.stdout.write to use a persistent streaming UTF-8 decoder instead of
decoding each buffer independently. Preserve decoder state across successive
reads, and reset that decoder whenever the truncation or rotation handling at
line 48 resets the file offset.
- Around line 28-29: Update the logs command around readLogTail so it reads
backward through multiple chunks rather than stopping after one 16 KiB chunk.
Continue until the requested lineCount newline delimiters are collected or the
beginning of the file is reached, while preserving the existing tail output
behavior.
In `@src/commands/status.ts`:
- Around line 93-109: Update readLogTail so a chunk without a newline is not
discarded when it contains the file’s final non-empty line; expand the read
window backward until a newline boundary is found, while preserving removal of
the initial partial line. Add a regression test covering a 17 KiB single-line
log and verify the tail remains truthy and is returned by the logs command.
In `@src/server/public.ts`:
- Around line 95-99: Update the public request handler and its response helpers,
including the no-slug path and sendErrorPage, to receive the request method and
suppress response bodies for every HEAD request. Preserve the existing status
codes and headers, but call res.end without content for HEAD while retaining
HTML bodies for GET.
In `@src/server/ws.ts`:
- Around line 47-57: The WebSocket client map currently uses the host-derived
slug instead of the canonical slug, preventing reload broadcasts from reaching
those clients. In the upgrade flow and the corresponding close and error
handlers, use a shared client key of resolved ?? slug when accessing
this.clients, while preserving the existing authentication and connection
behavior.
In `@src/storage/index.ts`:
- Around line 511-518: Update recordHit so repeated page views do not
continually reset the pending persistence deadline: preserve the hit and
timestamp updates, but ensure scheduleFlush retains an existing timer or
otherwise enforces a maximum flush interval. Use the existing scheduleFlush
mechanism and keep only one pending flush so sustained traffic eventually
persists the changes.
In `@test/api.test.ts`:
- Around line 389-397: Update the response Promise in the affected API test so
the `end` listener rejects with the actual status when it is not 200, rather
than throwing an assertion inside the callback; keep parsing and resolving the
JSON for successful responses, then move the status expectation to execute after
awaiting the Promise.
In `@test/cli.test.ts`:
- Around line 360-366: Strengthen the test case around the deploy invocation by
asserting that runCli(["deploy", f, "--protect", "hunter2"], ...) succeeds
before querying deployments. Update the JSON assertion to verify the protected
entry for the slug created by this test rather than accepting any protected
deployment in the shared daemon.home state, while retaining the access-key
non-leak assertion.
In `@test/config.test.ts`:
- Around line 115-118: The afterEach cleanup unconditionally assigns an
undefined HOME value, causing Node to store the literal "undefined". In
test/config.test.ts lines 115-118 and test/api-client.test.ts lines 25-28,
update the HOME restoration to delete process.env.HOME when the captured value
is undefined; otherwise restore the captured value, then retain the existing
fs.rmSync cleanup.
In `@test/global-setup.ts`:
- Line 20: Update the temp-directory name filter in the global setup cleanup
logic to allow digits in the prefix segment, so names such as uptool-api-utf8-*
are swept while retaining the existing uptool- prefix and trailing-hyphen
requirements.
In `@test/helpers.ts`:
- Around line 188-192: Update startDaemon to continuously drain both
child.stdout and child.stderr with data handlers, retaining only a bounded
recent-output buffer. When waitForPort fails or times out, include the buffered
stdout and stderr tail in the startup error while preserving the existing
successful startup behavior.
In `@test/status.test.ts`:
- Around line 414-441: Replace the fixed-delay settle helper in the followLog
tests with a deadline-based waitFor helper that repeatedly checks for the
expected emitted content and times out clearly; update both append and
truncation tests to use it and raise their test timeout as needed. Keep a fixed
short delay for the stop() releases the watcher absence assertion, or use
waitFor with a rejects assertion.
In `@test/storage.test.ts`:
- Around line 771-787: Update the version-ID generation used by ManifestStore
update/version persistence in src/storage/index.ts so consecutive updates within
the same millisecond always receive distinct IDs; when Date.now() matches an
existing newest version, append or increment a deterministic suffix (or
equivalent unique value). Ensure the generated ID is unique before creating the
version directory and adding it to entry.versions, preserving rollback and
pruning behavior without duplicate manifest entries.
In `@test/ws.test.ts`:
- Around line 62-66: Update the cleanup call in the server.close callback to
pass force: true alongside recursive: true when invoking fs.rmSync on tmpDir,
ensuring cleanup remains idempotent and resolve() is reached if the directory
was already removed.
---
Nitpick comments:
In `@test/api.test.ts`:
- Around line 409-413: Update the cleanup in the test’s finally block to remove
tmpDir2 with recursive and force options so an already-absent directory does not
mask the original failure. Also guard bigStore.flushNow() as needed so cleanup
does not write to or recreate the directory before removal.
In `@test/global-setup.ts`:
- Around line 19-29: Update the cleanup loop around readdirSync in the global
teardown to avoid deleting active concurrent-run directories: inspect each
matching entry’s modification time and remove it only when it exceeds the chosen
stale-age threshold. Preserve the existing recursive, forced removal and
best-effort error handling for eligible entries.
In `@test/public.test.ts`:
- Around line 516-522: Remove the stale “Handler throw -> 500, not a dead
daemon” section header from above the “View counting (recordHit)” block; keep
the existing handler-throw test and view-counting section marker aligned with
their respective tests.
In `@test/storage.test.ts`:
- Around line 547-568: Update the base64 size estimation test to exercise the
production estimator used by storage code instead of duplicating its formula
inline. Export and import that estimator from the relevant storage module, then
call it for each padding case while retaining the decoded-length assertions;
alternatively, test store() with max_file_size thresholds immediately above and
below the true decoded size.
In `@test/ws.test.ts`:
- Around line 170-182: Update the timer setup in the heartbeat test around
WsManager construction to fake only setInterval and clearInterval, leaving
setImmediate and other real event-loop APIs available for connectLr() websocket
I/O. Preserve the existing timer advancement and cleanup behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 284007ca-7ed7-4547-a09b-e369e88a13c0
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (38)
.github/workflows/ci.yml.gitignoreCHANGELOG.mdREADME.mdpackage.jsonplan-uptool-hardening-observabilidad.htmlsrc/cli.tssrc/commands/admin.tssrc/commands/deploy.tssrc/commands/init.tssrc/commands/list.tssrc/commands/logs.tssrc/commands/mcp.tssrc/commands/rm.tssrc/commands/rollback.tssrc/commands/serve.tssrc/commands/status.tssrc/lib/api-client.tssrc/lib/basic-auth.tssrc/lib/slug.tssrc/server/admin.tssrc/server/api.tssrc/server/public.tssrc/server/ws.tssrc/storage/index.tstest/api-client.test.tstest/api.test.tstest/cli.test.tstest/config.test.tstest/deploy.test.tstest/global-setup.tstest/helpers.test.tstest/helpers.tstest/public.test.tstest/status.test.tstest/storage.test.tstest/ws.test.tsvitest.config.ts
💤 Files with no reviewable changes (3)
- src/commands/mcp.ts
- src/server/admin.ts
- src/commands/admin.ts
| const tail = readLogTail(file, lineCount); | ||
| if (tail) console.log(tail); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Honor requested line counts above 16 KiB.
Line 28 calls readLogTail, which reads only one 16 KiB chunk. Therefore, uptool logs -n 10000 silently returns only the lines that fit in the final 16 KiB. Read backward in chunks until the requested number of newline delimiters is found or the file start is reached.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/commands/logs.ts` around lines 28 - 29, Update the logs command around
readLogTail so it reads backward through multiple chunks rather than stopping
after one 16 KiB chunk. Continue until the requested lineCount newline
delimiters are collected or the beginning of the file is reached, while
preserving the existing tail output behavior.
- Use canonical slug for deployment URLs and WebSocket broadcasts (fix routing via name) - StringDecoder for followLog: handles multi-byte UTF-8 split across reads - readLogTail: widen window for long lines (no newline in initial chunk) - ManifestStore: keep pending flush timer, don't reset on every hit - Version IDs: use monotonic timestamp to avoid collisions - Test: improve daemon error reporting, fix fd/env cleanup, stabilize watchers
Summary
--updateredeploys. Shown inuptool listoutput.uptool list --json: Machine-readable output for scripts and LLM automation. Access keys of protected deployments excluded.uptool logs: Read daemon logs directly (supports-n <lines>,-fto follow) without going throughuptool status. Works even when daemon is down.deploy --nameoutput, unprotected WebSocket in protected deployments, invalid HTTP method handling, log truncation at 16 KB boundary, uncaught manifest flush exceptions.uptool mcp) and admin web UI (uptool admin). Use CLI directly.@vitest/coverage-v8for coverage reporting, CI workflow now runs typecheck and enforces coverage thresholds.Testing
npm run typecheck— Type checking passesnpm run test:coverage— All tests pass with coverage thresholds metuptool list— Shows view counts and last-seen timesuptool list --json— Valid JSON array with all fields (no keys in protected deployments)uptool logs— Reads daemon logs, survives rotation with-fHEADrequests — No body in responseSummary by CodeRabbit
New Features
uptool logswith line limits and live-follow mode.Bug Fixes
Breaking Changes
Documentation